﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

using NHibernate;
using NHibernate.Criterion;
using FJASPX.Framwork.Query;
using NHibernate.Impl;
using Spring.Data.NHibernate.Generic.Support;

namespace FJASPX.Framwork.Dao
{
    /// <summary>
    /// 泛型基类
    /// </summary>
    public partial class NHGenericDao : HibernateDaoSupport
    {

        #region Transcation
        public void Transcation(Action action)
        {
            ITransaction transcation = this.Session.BeginTransaction();
            try
            {
                action();
                transcation.Commit();
            }
            catch
            {
                transcation.Rollback();
                throw;
            }
        }
        public void Transcation(Action action, System.Data.IsolationLevel isolationLevel)
        {
            ITransaction transcation = this.Session.BeginTransaction(isolationLevel);
            try
            {
                action();
                transcation.Commit();
            }
            catch
            {
                transcation.Rollback();
                throw;
            }
        }
        #endregion

        #region"lock"
        /// <summary>
        /// 写锁(仅在事务环境上有效) 本方法是事务安全的.
        /// </summary>
        /// <param name="entity"></param>
        public void Lock(object entity)
        {
            this.HibernateTemplate.Lock(entity, LockMode.Upgrade);
        }
        /// <summary>
        /// 读锁(仅在事务环境上有效) 本方法是事务安全的.
        /// </summary>
        /// <param name="entity"></param>
        public void LockForRead(object entity)
        {
            this.HibernateTemplate.Lock(entity, LockMode.Read);
        }
        #endregion

        #region"增、删、改"
        /// <summary>
        /// 根据ID获取对象. 实际调用NHibernate的this.HibernateTemplate.load()方法返回实体或其proxy对象. 如果对象不存在，抛出异常. 本方法是事务安全的.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public T Get<T>(object id)
        {
            return this.HibernateTemplate.Get<T>(id);
        }
        public T SafeGet<T>(object id)
        {
            return this.HibernateTemplate.Get<T>(id);
        }
        /// <summary>
        /// 根据ID获取对象. 实际调用NHibernate的this.HibernateTemplate.get()方法返回实体或其proxy对象. 如果对象不存在，返回Null. 本方法是事务安全的.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public T Load<T>(object id)
        {
            return this.HibernateTemplate.Load<T>(id);
        }
        /// <summary>
        /// 获取全部对象. 本方法是事务安全的.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> GetAll<T>() where T : class
        {
            return GetAll<T>(null, false);
        }
        /// <summary>
        /// 获取全部对象,带排序字段与升降序参数. 本方法是事务安全的.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="orderBy"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public IList<T> GetAll<T>(string orderBy, bool isAsc) where T : class
        {
            ICriteria query = this.Session.CreateCriteria<T>();
            ICriteria queryPage = CriteriaTransformer.Clone(query);
            if (isAsc)
            {
                //设置排序
                if (orderBy != null)
                {
                    queryPage.AddOrder(Order.Asc(orderBy));
                }
            }
            else
            {
                //设置排序
                if (orderBy != null)
                {
                    queryPage.AddOrder(Order.Desc(orderBy));
                }
            }
            return queryPage.List<T>();
        }

        public void Insert(object entity)
        {
            this.HibernateTemplate.SaveOrUpdate(entity);
            this.HibernateTemplate.Flush();
        }
        /// <summary>
        /// 保存指定实体名的实体
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="entity"></param>
        public void Insert(string entityName, object entity)
        {
            this.HibernateTemplate.Save(entityName, entity);
            this.HibernateTemplate.Flush();
        }
        public void InsertOrUpdate(object entity)
        {
            this.HibernateTemplate.SaveOrUpdate(entity);
            this.HibernateTemplate.Flush();
        }
        /// <summary>
        /// 批量保存
        /// </summary>
        public void BulkInsert(List<object> entityList)
        {
            if (entityList != null && entityList.Count > 0)
            {
                foreach (var entity in entityList)
                {
                    this.HibernateTemplate.Save(entity);
                }
            }
        }

        public void Update(object entity)
        {
            this.HibernateTemplate.Update(entity);
            this.HibernateTemplate.Flush();
        }


        #region"删除"
        /// <summary>
        /// 根据实体对象删除
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(object entity)
        {
            this.HibernateTemplate.Delete(entity);
            this.HibernateTemplate.Flush();
        }
        /// <summary>
        /// 根据实体名移除实体对象
        /// </summary>
        /// <param name="entityName"></param>
        /// <param name="entity"></param>
        public void Delete(string entityName, object entity)
        {
            this.Session.Delete(entityName, entity);
        }
        /// <summary>
        /// 根据ID删除对象. 本方法是事务安全的.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        public void DeleteById<T>(object id)
        {
            var entity = this.HibernateTemplate.Get<T>(id);
            if (entity == null)
            {
                return;
            }
            this.HibernateTemplate.Delete(entity);
        }
        /// <summary>
        /// 根据ID数组删除对象. 本方法是事务安全的.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ids"></param>
        public void DeleteByIds<T>(object[] ids)
        {
            foreach (var id in ids)
            {
                DeleteById<T>(id);
            }
        }
        /// <summary>
        /// 根据hql语句删除
        /// </summary>
        /// <example>hql="from 类名 where 属性名=值"</example>
        /// <param name="hql"></param>
        public void DeleteByQuery(string hql)
        {
            this.HibernateTemplate.Delete(hql);
            this.HibernateTemplate.Flush();
        }
        /// <summary>
        /// 批量删除,本方法是非事务安全的.
        /// </summary>
        /// <param name="entityName">实体名</param>
        /// <param name="ids">实体id数组</param>
        public void BatchDeleteByIds(string entityName, object[] ids)
        {
            StringBuilder hql = new StringBuilder();
            hql.Append("delete from ").Append(entityName).Append(" where id in (:ids) ");
            IQuery query = this.Session.CreateQuery(hql.ToString());
            query.SetParameterList("ids", ids);
            query.ExecuteUpdate();
        }
        /// <summary>
        /// 根据Query进行删除
        /// <example>
        /// hql="delete from 类名 where 属性名=:参数名";
        /// </example>
        /// </summary>
        /// <param name="hql">hql语句</param>
        /// <param name="name">参数名称</param>
        /// <param name="value">参数值</param>
        public void DeleteByQuery(string hql, string name, object value)
        {
            DeleteByQuery(hql, new string[] { name }, new object[] { value });
        }
        /// <summary>
        /// 根据Query进行删除
        /// <example>
        /// hql="delete from 类名 where 属性名=:参数名";
        /// </example>
        /// </summary>
        /// <param name="hql">hql语句</param>
        /// <param name="names">参数名称数组</param>
        /// <param name="values">参数值数组</param>
        public void DeleteByQuery(string hql, string[] names, object[] values)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            query.ExecuteUpdate();
            this.HibernateTemplate.Flush();
        }
        /// <summary>
        /// 根据Query进行删除
        /// <example>
        /// hql="delete from 类名 where 属性名=? and 属性名=？";
        /// </example>
        /// </summary>
        /// <param name="hql">hql语句</param>
        /// <param name="values">参数值数组</param>
        public void DeleteByQuery(string hql, object[] values)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            query.ExecuteUpdate();
            this.HibernateTemplate.Flush();
        }

        #endregion
        #endregion

        #region Count
        public int Count<T>() where T : class
        {
            ICriteria criteria = this.Session.CreateCriteria<T>();
            return Convert.ToInt32(criteria.SetProjection(Projections.RowCount()).UniqueResult());
        }

        public int Count<T>(ICriterion expression) where T : class
        {
            ICriteria criteria = this.Session.CreateCriteria<T>();
            if (expression != null)
            {
                criteria.Add(expression);
            }
            return Convert.ToInt32(criteria.SetProjection(Projections.RowCount()).UniqueResult());
        }

        #endregion

        #region Scalar

        public object Scalar(string hql)
        {
            return this.Session.CreateQuery(hql).UniqueResult();
        }

        public object Scalar(string hql, params object[] values)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            return query.UniqueResult();
        }

        public object Scalar(string hql, string name, object value)
        {
            return Scalar(hql, new string[] { name }, new object[] { value });
        }

        public object Scalar(string hql, string[] names, object[] values)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            return query.UniqueResult();
        }

        public object Scalar(string hql, Action<IQuery> action)
        {
            IQuery query = this.Session.CreateQuery(hql);
            action(query);
            return query.UniqueResult();
        }

        #endregion

        #region ScalarBySQL

        public object ScalarBySQL(string sql)
        {
            return this.Session.CreateSQLQuery(sql).UniqueResult();
        }

        public object ScalarBySQL(string sql, params object[] values)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            return query.UniqueResult();
        }

        public object ScalarBySQL(string sql, string name, object value)
        {
            return ScalarBySQL(sql, new string[] { name }, new object[] { value });
        }

        public object ScalarBySQL(string sql, string[] names, object[] values)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            return query.UniqueResult();
        }

        public object ScalarBySQL(string sql, Action<ISQLQuery> action)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            action(query);
            return query.UniqueResult();
        }
        #endregion

        #region Query

        public IList<T> Query<T>() where T : class
        {
            return this.Session.CreateCriteria<T>().List<T>();
        }

        public IList<T> Query<T>(Action<ICriteria> action) where T : class
        {
            ICriteria criteria = this.Session.CreateCriteria<T>();
            action(criteria);
            return criteria.List<T>();
        }

        public IList<T> Query<T>(ICriterion expression) where T : class
        {
            return Query<T>(expression, null);
        }

        public IList<T> Query<T>(ICriterion expression, Action<ICriteria> action) where T : class
        {
            ICriteria criteria = this.Session.CreateCriteria<T>();
            if (expression != null)
            {
                criteria.Add(expression);
            }
            if (action != null)
            {
                action(criteria);
            }
            return criteria.List<T>();
        }

        public IList<T> Query<T>(string hql)
        {
            return this.Session.CreateQuery(hql).List<T>();
        }

        public IList<T> Query<T>(string hql, object[] values)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            return query.List<T>();
        }

        public IList<T> Query<T>(string hql, string name, object value)
        {
            return Query<T>(hql, new string[] { name }, new object[] { value });
        }

        public IList<T> Query<T>(string hql, string[] names, object[] values)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            return query.List<T>();
        }

        public IList<T> Query<T>(string hql, Action<IQuery> action)
        {
            IQuery query = this.Session.CreateQuery(hql);
            action(query);
            return query.List<T>();
        }

        #endregion

        #region Page Query

        public IList<T> Query<T>(int pageIndex, int pageSize, out long recordCount) where T : class
        {
            ICriterion c = null;
            return Query<T>(c, null, pageIndex, pageSize, out recordCount);
        }

        public IList<T> Query<T>(ICriterion expression, int pageIndex, int pageSize, out long recordCount) where T : class
        {
            return Query<T>(expression, null, pageIndex, pageSize, out recordCount);
        }

        public IList<T> Query<T>(List<ICriterion> expressions, List<Order> order,
    int pageIndex, int pageSize, out long recordCount) where T : class
        {
            IList<T> list = new List<T>();
            recordCount = 0;
            ICriteria query = this.Session.CreateCriteria<T>();
            if (expressions != null)
            {
                foreach (var c in expressions)
                {
                    query.Add(c);
                }
            }
            ICriteria queryPage = CriteriaTransformer.Clone(query);
            //获取记录总数
            recordCount = Convert.ToInt32(query.SetProjection(Projections.RowCount()).UniqueResult());

            //设置排序
            if (order != null)
            {
                foreach (Order o in order)
                {
                    queryPage.AddOrder(o);
                }
            }
            queryPage.SetFirstResult((pageIndex) * pageSize);
            queryPage.SetMaxResults(pageSize);
            list = queryPage.List<T>();

            return list;
        }

        public IList<T> Query<T>(ICriterion expression, List<Order> order,
            int pageIndex, int pageSize, out long recordCount) where T : class
        {
            IList<T> list = new List<T>();
            recordCount = 0;
            ICriteria query = this.Session.CreateCriteria<T>();
            if (expression != null)
            {
                query.Add(expression);
            }
            ICriteria queryPage = CriteriaTransformer.Clone(query);
            //获取记录总数
            recordCount = Convert.ToInt32(query.SetProjection(Projections.RowCount()).UniqueResult());

            //设置排序
            if (order != null)
            {
                foreach (Order o in order)
                {
                    queryPage.AddOrder(o);
                }
            }
            queryPage.SetFirstResult((pageIndex) * pageSize);
            queryPage.SetMaxResults(pageSize);
            list = queryPage.List<T>();

            return list;
        }

        public IList<T> Query<T>(string hql, object[] values, int pageIndex, int pageSize)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            return query.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List<T>();
        }

        public IList<T> Query<T>(string hql, string name, object value, int pageIndex, int pageSize)
        {
            return Query<T>(hql, new string[] { name }, new object[] { value }, pageIndex, pageSize);
        }

        public IList<T> Query<T>(string hql, string[] names, object[] values, int pageIndex, int pageSize)
        {
            IQuery query = this.Session.CreateQuery(hql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            return query.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List<T>();
        }

        public IList<T> Query<T>(string hql, int pageIndex, int pageSize)
        {
            IQuery query = this.Session.CreateQuery(hql);
            return query.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List<T>();
        }

        #endregion

        #region SQL Query

        public IList QueryBySQL(string sql)
        {
            return this.Session.CreateSQLQuery(sql).List();
        }

        public IList QueryBySQL(string sql, params object[] values)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            return query.List();
        }

        public IList QueryBySQL(string sql, string name, object[] value)
        {
            return QueryBySQL(sql, new string[] { name }, new object[] { value });
        }

        public IList QueryBySQL(string sql, string[] names, object[] values)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            return query.List();
        }

        public IList QueryBySQL(string sql, Action<ISQLQuery> action)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            action(query);
            return query.List();
        }

        #endregion

        #region Page SQL Query

        public IList QueryBySQL(string sql, object[] values, int pageIndex, int pageSize)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            for (int i = 0; i < values.Length; i++)
            {
                query.SetParameter(i, values[i]);
            }
            return query.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List();
        }

        public IList QueryBySQL(string sql, string name, object value, int pageIndex, int pageSize)
        {
            return QueryBySQL(sql, new string[] { name }, new object[] { value }, pageIndex, pageSize);
        }

        public IList QueryBySQL(string sql, string[] names, object[] values, int pageIndex, int pageSize)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            for (int i = 0; i < names.Length; i++)
            {
                query.SetParameter(names[i], values[i]);
            }
            return query.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List();
        }

        public IList QueryBySQL(string sql, int pageIndex, int pageSize)
        {
            ISQLQuery query = this.Session.CreateSQLQuery(sql);
            return query.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List();
        }

        #endregion


        #region"other"
        public void Flush()
        {
            this.HibernateTemplate.Flush();
        }
        public void Clear()
        {
            this.HibernateTemplate.Clear();
        }
        /// <summary>
        /// 同步对象（获取最新数据库状态）. 本方法是事务安全的.
        /// </summary>
        /// <param name="entity"></param>
        public void Refresh(object entity)
        {
            this.HibernateTemplate.Refresh(entity);
        }
        #endregion


    }
}
